package com.rzt.cft.utils;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.RandomUtil;
import org.springframework.lang.Nullable;

import java.lang.reflect.Constructor;
import java.math.BigDecimal;
import java.sql.Timestamp;
import java.util.*;
import java.util.function.BinaryOperator;
import java.util.function.Function;
import java.util.function.Predicate;
import java.util.stream.Collectors;

/**
 * 对象copy工具类
 * 2019/12/10
 */
public class CustomUtil {

    public static final char UNDERLINE = '_';

    /**
     * copy 对象属性
     *
     * @param s
     * @param tClass
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> T maping(S s, Class<T> tClass) {
        if (Objects.isNull(s))
            return null;
        try {
            Constructor c0 = tClass.getDeclaredConstructor();
            c0.setAccessible(true);
            T t = (T) c0.newInstance();
            BeanUtil.copyProperties(s, t);
            return t;
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * copy 集合
     *
     * @param sourceList
     * @param tclass
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> List<T> maping(Collection<S> sourceList, Class<T> tclass) {
        return sourceList.stream().map(x -> maping(x, tclass)).collect(Collectors.toList());
    }

    /**
     * 对象转换
     *
     * @param sourceList
     * @param mapper
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> List<T> select(Collection<S> sourceList, Function<? super S, ? extends T> mapper) {
        return sourceList.stream().map(mapper).collect(Collectors.toList());
    }

    /**
     * 条件查询
     *
     * @param sourceList
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> List<T> where(Collection<T> sourceList, Predicate<? super T> predicate) {
        return sourceList.stream().filter(predicate).collect(Collectors.toList());
    }

    /**
     * 获取第一条
     *
     * @param sourceList
     * @param <T>
     * @return
     */
    public static <T> T first(Collection<T> sourceList) {
        return sourceList.stream().findFirst().orElse(null);
    }

    /**
     * 获取第一条
     *
     * @param sourceList
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> T first(Collection<T> sourceList, Predicate<? super T> predicate) {
        return sourceList.stream().filter(predicate).findFirst().orElse(null);
    }

    /**
     * 是否包含
     * @param sourceList
     * @param predicate
     * @param <T>
     * @return
     */
    public static <T> Boolean contains(Collection<T> sourceList, Predicate<? super T> predicate){
        return sourceList.stream().filter(predicate).anyMatch(predicate);
    }

    /**
     * 排序(升序)
     *
     * @param sourceList
     * @param func
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> List<T> orderBy(Collection<T> sourceList, Function<? super T, ? extends S> func) {
        return sourceList.stream().sorted((o1, o2) -> {
                    S s1 = func.apply(o1);
                    S s2 = func.apply(o2);
                    return compareTo(s1, s2);
                }
        ).collect(Collectors.toList());
    }

    /**
     * 分组
     * @param sourceList
     * @param func
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T,S> Map<S,List<T>> groupBy(Collection<T> sourceList, Function<? super T, ? extends S> func){
       return sourceList.stream().collect(Collectors.groupingBy(func));
    }

    /**
     * 获取最大值
     *
     * @param sourceList
     * @param func
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> S max(Collection<T> sourceList, Function<? super T, ? extends S> func) {
        List<T> list = orderByDesc(sourceList, func);
        return func.apply(CustomUtil.first(list));
    }

    /**
     * 获取最小值
     *
     * @param sourceList
     * @param func
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> S min(Collection<T> sourceList, Function<? super T, ? extends S> func) {
        List<T> list = orderBy(sourceList, func);
        return func.apply(CustomUtil.first(list));
    }

    /**
     * 获取可空属性值
     *
     * @param source 数据源 为NULL时返回NULL
     * @param func
     * @param <T>
     * @param <S>
     * @return
     */
    @Nullable
    public static <T, S> S value(T source, Function<T, S> func) {
        if (Objects.isNull(source))
            return null;
        return func.apply(source);
    }

    /**
     * 获取属性值
     *
     * @param source       数据源 为NULL时返回默认值
     * @param func
     * @param defaultValue
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> S value(T source, Function<T, S> func, S defaultValue) {
        if (Objects.isNull(source))
            return defaultValue;
        S value = func.apply(source);
        return Objects.isNull(value) ? defaultValue : value;
    }

    /**
     * 防止获取null值
     *
     * @param source
     * @param defaultValue
     * @param <S>
     * @return
     */
    public static <S> S value(S source, S defaultValue) {
        if (Objects.isNull(source)) {
            return defaultValue;
        }
        return source;
    }

    /**
     * 是否为true
     *
     * @param source
     * @param func
     * @param <T>
     * @return
     */
    public static <T> boolean isTrue(T source, Function<T, Boolean> func) {
        if (Objects.isNull(source))
            return false;
        Boolean result = func.apply(source);
        return !Objects.isNull(result) ? result : false;
    }

    /**
     * 求和
     *
     * @param sourceList  数据源
     * @param func        指定字段
     * @param initValue   初始值
     * @param accumulator 运算方式
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> S sum(Collection<T> sourceList, Function<T, S> func, S initValue, BinaryOperator<S> accumulator) {
        List<S> list = where(select(sourceList, func), Objects::nonNull);
        return list.parallelStream().reduce(initValue, accumulator);
    }


    /**
     * 排序(降序)
     *
     * @param sourceList
     * @param func
     * @param <T>
     * @param <S>
     * @return
     */
    public static <T, S> List<T> orderByDesc(Collection<T> sourceList, Function<? super T, ? extends S> func) {
        List<T> list = orderBy(sourceList, func);
        Collections.reverse(list);
        return list;
    }

    /**
     * 对象转Map 进行驼峰转下划线，忽略值为空的字段
     *
     * @param bean  bean对象
     * @return Map
     */
    public static Map<String, Object> beanToMap(Object bean) {
        return BeanUtil.beanToMap(bean, new LinkedHashMap<>(), true, true);
    }

    public static String[] toArrayString(Collection<String> sourceList) {
        return sourceList.toArray(new String[]{});
    }

    /**
     * 排序比对
     *
     * @param s1  值1
     * @param s2  值2
     * @param <S> 值类型
     * @return
     */
    public static <S> int compareTo(S s1, S s2) {
        if (Objects.isNull(s1) && Objects.isNull(s2))
            return 0;
        if (Objects.isNull(s1))
            return -1;
        if (Objects.isNull(s2))
            return 1;

        // int
        if (s1 instanceof Integer) {
            Integer is1 = (Integer) s1;
            return is1.compareTo((Integer) s2);
        }
        if (s1 instanceof Double) {
            Double ds1 = (Double) s1;
            return ds1.compareTo((Double) s2);
        }
        if (s1 instanceof Float) {
            Float fs1 = (Float) s1;
            return fs1.compareTo((Float) s2);
        }
        if (s1 instanceof Long) {
            Long ls1 = (Long) s1;
            return ls1.compareTo((Long) s2);
        }
        if (s1 instanceof BigDecimal) {
            BigDecimal bd1 = (BigDecimal) s1;
            return bd1.compareTo((BigDecimal) s2);
        }
        if (s1 instanceof Timestamp) {
            Timestamp ts1 = (Timestamp) s1;
            return ts1.compareTo((Timestamp) s2);
        }

        String str1 = s1.toString();
        return str1.compareTo(s2.toString());
    }

    /**
     * 去重
     *
     * @param sourceList
     * @param <T>
     * @return
     */
    public static <T> List<T> distinct(Collection<T> sourceList) {
        Set<T> set = new LinkedHashSet<>(sourceList);
        return new ArrayList<>(set);
    }

    /**
     * java8特性 去重
     *
     * @param sourceList
     * @param <T>
     * @return
     */
    public static <T> List<T> distinct8(Collection<T> sourceList) {
        return sourceList.stream().distinct().collect(Collectors.toList());
    }

    /**
     * 驼峰格式字符串转换为下划线格式字符串
     *
     * @param param
     * @return
     */
    public static String camelToUnderline(String param) {
        if (param == null || "".equals(param.trim())) {
            return "";
        }
        int len = param.length();
        StringBuilder sb = new StringBuilder(len);
        for (int i = 0; i < len; i++) {
            char c = param.charAt(i);
            if (Character.isUpperCase(c)) {
                sb.append(UNDERLINE);
                sb.append(Character.toLowerCase(c));
            } else {
                sb.append(c);
            }
        }
        return sb.toString();
    }

    public static <T> T getNewObject(Class<T> tClass) {
        try {
            Constructor c0 = tClass.getDeclaredConstructor();
            c0.setAccessible(true);
            T t = (T) c0.newInstance();
            return t;
        } catch (Exception ex) {
            return null;
        }
    }

    /**
     * 生成code
     * @return
     */
    public static String getSsn() {
        String time = DateUtil.format(new Date(), "yyyyMMddHHmmssSSS");
        return time + RandomUtil.randomNumbers(6);
    }

    /**
     * 生成code
     * @param count
     * @return
     */
    public static String getCode(Integer count) {
        String time = DateUtil.format(new Date(), "MM");
        return time + RandomUtil.randomNumbers(6) + count;
    }

    /**
     * 生成随机数
     * @param num
     * @return
     */
    public static String getRandomNum(Integer num) {
        String base = "0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }

    /**
     * 生成随机字符串
     * @param num
     * @return
     */
    public static String getRandomString(Integer num) {
        String base = "abcdefghijklmnopqrstuvwxyz0123456789";
        Random random = new Random();
        StringBuffer sb = new StringBuffer();
        for (int i = 0; i < num; i++) {
            int number = random.nextInt(base.length());
            sb.append(base.charAt(number));
        }
        return sb.toString();
    }
}